﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleScratchCard
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Parse("2015-6-11 21:00:00");
            DateTime endTime = DateTime.Parse("2015-6-11 23:00:00");
            var luckybox = new LuckyBox(startTime, endTime, 2, 3, 50, 0, 0, 0);

            while (true)
            {
                var command = Console.ReadLine();
                var prize = luckybox.WinLottery(DateTime.Now, "abc");
                Console.WriteLine(prize);
            }
        }
    }

    public class LuckyBox
    {
        private List<ReleasePrizeModel> _releasePrizeModels;
        private List<ReleasePrizeModel> _releasedPrizeModels;
        private double _deltaTime;
        private double _total;
        private DateTime _startTime;


        public LuckyBox(DateTime startTime, DateTime endTime, int grandPrizeCount, int firstPrizeCount, int secondPrizeCount, int thirdPrizeCount, int forthPrizeCount, int fifthPrizeCount)
        {
            _startTime = startTime;
            _releasedPrizeModels = new List<ReleasePrizeModel>();
            _total = grandPrizeCount + firstPrizeCount + secondPrizeCount + thirdPrizeCount + forthPrizeCount + fifthPrizeCount;
            _deltaTime = endTime.Subtract(startTime).TotalSeconds / _total;
            _releasePrizeModels = DistributePrize(grandPrizeCount, firstPrizeCount, secondPrizeCount, thirdPrizeCount, forthPrizeCount, fifthPrizeCount);
        }

        private List<ReleasePrizeModel> DistributePrize(int grandPrizeCount, int firstPrizeCount, int secondPrizeCount, int thirdPrizeCount, int forthPrizeCount, int fifthPrizeCount)
        {
            var list = new List<PrizeModel>
            {
                new PrizeModel(grandPrizeCount, Prize.Grand),
                new PrizeModel(firstPrizeCount, Prize.First),
                new PrizeModel(secondPrizeCount, Prize.Second),
                new PrizeModel(thirdPrizeCount, Prize.Third),
                new PrizeModel(forthPrizeCount, Prize.Forth),
                new PrizeModel(fifthPrizeCount, Prize.Fifth),
            }.OrderByDescending(o => o.Count).ToList();
            #region 根据权重分配，貌似不怎么合适。
            //var totoal = list.Sum(o => o.Count);
            //while (totoal > 0)
            //{
            //    var random = new Random();
            //    var value = random.Next(1, totoal);

            //    var m = 0;
            //    foreach (var model in list.OrderBy(o => o.Count))
            //    {
            //        m += model.Count;
            //        if (value <= m)
            //        {
            //            releasePrizeModels.Add(new ReleasePrizeModel(model.Prize)
            //            {
            //                ReleaseTime= _startTime.AddSeconds((releasePrizeModels.Count - 1) * _deltaTime + new Random().NextDouble() * _deltaTime)
            //            });
            //            model.Count--;
            //        }
            //    }

            //    totoal = list.Sum(o => o.Count);
            //}
            #endregion
            int i = 0;
            var item1 = BuilderList(list[i]);
            while (i < list.Count())
            {
                i++;
                if (i == list.Count) continue;
                var item2 = BuilderList(list[i]);

                if (item2.Count == 0) continue;
                var m = item1.Count / item2.Count;

                var nodeList = new List<ReleasePrizeModel>();
                for (int j = 0; j <= item2.Count; j++)
                {
                    var temp = item1.Skip(j * m).Take(m).ToList();
                    if (j != item2.Count)
                    {
                        Random r = new Random();
                        var value = r.Next(1, temp.Count);
                        temp.Insert(value, item2[j]);
                    }

                    nodeList.AddRange(temp);
                }

                item1 = nodeList ;
            }

            for (int m   = 0; m < item1.Count; m++)
            {
                var item = item1[m];
                item.ReleaseTime = _startTime.AddSeconds((m - 1) * _deltaTime + new Random().NextDouble() * _deltaTime);
            }

            return item1;
        }

        private List<ReleasePrizeModel> BuilderList(PrizeModel prizeModel)
        {
            var tempK = new List<ReleasePrizeModel>();
            for (int k = 0; k < prizeModel.Count; k++)
            {
                tempK.Add(new ReleasePrizeModel(prizeModel.Prize));
            }
            return tempK;
        }

        public Prize WinLottery(DateTime dtNow, string userId)
        {
            Prize prize = Prize.ThankYou;
            var models = _releasePrizeModels.Where(o => dtNow >= o.ReleaseTime); //获取应该释放的奖品

            var model = models.FirstOrDefault();

            if(model != null)
            {
                model.Release(dtNow, userId);

                _releasePrizeModels.Remove(model);
                _releasedPrizeModels.Add(model);
                prize = model.Prize;
            }

            return prize;
        }

        public enum Prize
        {
            Grand = 0,
            First = 1,
            Second = 2,
            Third = 3,
            Forth = 4,
            Fifth = 5,
            ThankYou = 10,
        }

        public class PrizeModel
        {
            public int Count { get; set; }
            public Prize Prize { get;private set; }

            public PrizeModel(int count, Prize prize)
            {
                Count = count;
                Prize = prize;
            }

            public override string ToString()
            {
                return string.Format("{0}|{1}",Prize,Count);
            }
        }

        public class ReleasePrizeModel
        {
            public ReleasePrizeModel(Prize prize)
            {
                Prize = prize;
            }

            public Prize Prize { get; set; }
            public DateTime ReleaseTime { get; set; }

            public DateTime ReleasedTime { get; private set; }
            public string ReleasedUserId { get; private set; }

            internal void Release(DateTime dtNow, string userId)
            {
                ReleasedTime = dtNow;
                ReleasedUserId = userId;
            }

            public override string ToString()
            {
                return  string.Format("{0}|{1}",Prize,ReleaseTime);
            }
        }


        public static List<T> Randomize<T>(List<T> list)
        {
            List<T> randomizedList = new List<T>();
            Random rnd = new Random();
            while (list.Count > 0)
            {
                int index = rnd.Next(0, list.Count); //pick a random item from the master list
                randomizedList.Add(list[index]); //place it at the end of the randomized list
                list.RemoveAt(index);
            }
            return randomizedList;
        }
    }
}
